home *** CD-ROM | disk | FTP | other *** search
- Subject: v13i035: Binary file editor
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Johan Vromans <mcvax!mh.nl!jv>
- Posting-number: Volume 13, Issue 35
- Archive-name: zap
-
- [ This is a simple little editor for binary-type files. It works under
- Unix, VMS, and MS-DOS. I'm not sure what "no military use means";
- don't zap the enemy, I guess. --r$ ]
-
-
- Features include -
-
- - looking at the file by byte, word or longword,
- - display contents in octal, hex, decimal and ascii,
- - searching for bytes/words/longwords
- - verification of changes
- - buffered update with optional checksum
- - runs on Unix, VAX/VMS and MS-DOS
-
- Zap mimics a program called SIPP (Save Image Patch Program), which
- was supplied by Digital Equipment Corp. with the RT-11 operating system.
-
- Distribution free as long as you give credit to the original author.
- Military use and explicit resale prohibited.
-
- Johan Vromans | jv@mh.nl via European backbone
- Multihouse N.V., Gouda, the Netherlands | uucp: ..{uunet!}mcvax!mh.nl!jv
- "It is better to light a candle than to curse the darkness"
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # Read.Me
- # zap.c
- # zap.1
- # Makefile
- # mkzap.com
- # mkzap.bat
- export PATH; PATH=/bin:/usr/bin:$PATH
- if test -f 'Read.Me'
- then
- echo shar: "will not over-write existing file 'Read.Me'"
- else
- cat << \SHAR_EOF > 'Read.Me'
- This is zap, a binary file inspector/patcher.
-
- Written by Johan Vromans at Multihouse Research, Gouda, the Netherlands.
- Copyright 1987 Johan Vromans.
- Distribution free as long as you give credit to the original author.
- Military use and explicit resale prohibited.
-
- Features include -
-
- - looking at the file by byte, word or longword,
- - display contents in octal, hex, decimal and ascii,
- - searching for bytes/words/longwords
- - verification of changes
- - buffered update with optional checksum
- - runs on Unix, VAX/VMS and MS-DOS
-
- Zap mimics a program called SIPP (Save Image Patch Program), which
- was supplied by Digital Equipment Corp. with the RT-11 operating system.
-
- ----------------
-
- Building zap
-
- Zap is pretty portable, mainly because it does not use difficult things.
- No shell escapes, no tty rubbish, only standard IO.
-
- The only thing which is important to zap is whether your system
- has byte ordering like a VAX or not.
- When it has its bytes ordered VAX-wise, you may compile zap with -DSWAB=1,
- otherwise use -DSWAB=0. If you are not sure: don't specify -DSWAB and zap
- will find out itself.
-
- This distribution contains:
-
- Read.Me this file
- zap.c C program source
- zap.1 nroff -man manual page
- Makefile makefile for unix
- mkzap.com compile for VAX/VMS
- mkzap.bat compile for MS-DOS
-
- ----------------
- Special notes for Unix:
-
- - the program has been tested on System V and BSD.
-
- - on swabbing and non-swabbing machines.
-
- Special notes for VAX/VMS:
-
- - the program has been tested with VAX-C (not VAX11C).
-
- - always compile with /DEFINE=(SWAB=2) (use the mkzap.com file).
-
- - performs well, but probably limited to stream-lf files.
-
- Special notes for MS-DOS:
-
- - the program has been tested with Microsoft C V4 using small model.
-
- - always compile with -DLINT_ARGS.
-
- ----------------
-
- Suggestions and enhancements are welcome!
-
- Johan Vromans, Multihouse Research
- Usenet: jv@mh.nl via european backbone mcvax.
-
- Disclaimer: Usage of this program is always at your own risk.
- SHAR_EOF
- if test 1992 -ne "`wc -c < 'Read.Me'`"
- then
- echo shar: "error transmitting 'Read.Me'" '(should have been 1992 characters)'
- fi
- fi
- if test -f 'zap.c'
- then
- echo shar: "will not over-write existing file 'zap.c'"
- else
- cat << \SHAR_EOF > 'zap.c'
- /* zap.c - program to inspect/patch binary files */
-
- static char SCCS_id[] = "@(#)@ zap 1.9 zap.c";
-
- static char cprght[] = "\
- @(#) Written by Johan Vromans at Multihouse Research, Gouda, the Netherlands.\n\
- @(#) Copyright 1987 Johan Vromans.\n\
- @(#) Distribution free as long as you give credit to the original author.\n\
- @(#) Military use and explicit resale prohibited.\n\
- @(#) Usage of this program is always at your own risk.";
-
- #include <stdio.h>
- #include <ctype.h>
- #include <signal.h>
-
- #ifndef TRUE
- # define TRUE 1
- # define FALSE 0
- #endif
-
- /* define SWAB=1 for byte swapping machines, such as vax and pdp-11 */
- /* otherwise, define it to 0 */
- /* if unknown, don't define it (or set it to 2) - zap will find out */
- /* when known, it is up to the C compiler to optimize unneeded code */
-
- #ifndef SWAB
- /* SWAB not defined - use info for machines we know */
- # ifdef vax /* DEC VAX */
- # define SWAB 1
- # endif
- # ifdef pdp11 /* DEC PDP-11 */
- # define SWAB 1
- # endif
- # ifdef hp9000s200 /* Hewlett-Packard HP9000/200 (M68xxx) */
- # define SWAB 0
- # endif
- # ifdef hp9000s500 /* Hewlett-Packard HP9000/500 (FocusII) */
- # define SWAB 0
- # endif
- # ifdef M_I86 /* Intel 86 family */
- # define SWAB 1
- # endif
- #endif
-
- #ifdef SWAB
- # if SWAB > 1 /* explicitly unknown */
- # undef SWAB
- # endif
- #endif
-
- #ifndef SWAB
- int swab = FALSE; /* use dynamic method */
- #else
- # define swab SWAB /* leave it to the compiler to eliminate */
- #endif
-
- /* About swabbing -
- *
- * Representation of data
- *
- * swabbing non-swabbing
- * type numeric character character
- * byte 0x61 'a' 'a'
- * word 0x6162 'ba' 'ab'
- * longword 0x61626364 'dcba' 'abcd'
- */
-
- #ifdef MSDOS
- # ifdef LINT_ARGS
-
- /* function defs as generated by MS-C V4.0 */
-
- /*global*/ int main (int, char**);
- /*global*/ int decod (char*, long*);
- /*global*/ unsigned int gv_file (long);
- /*global*/ int locate (long);
- /*global*/ int enter (long, int);
- /*global*/ int get_value (long);
- /*global*/ int put_value (long, long);
- /*global*/ int ptv_file (long, char);
- /*global*/ int push_loc (long);
- /*global*/ long pop_loc (void);
- /*global*/ int quit_search (void);
- /*global*/ int search (void);
- /*global*/ int verify (void);
- /*global*/ int gt_line (char*, char*, long, long, char, char*);
- /*global*/ int gt_val (char*, long*);
- /*global*/ char* pr_val (long, int);
- /*global*/ int zap (char*);
- /*global*/ int cant (char*);
- /*global*/ int remark (char*, long);
- /*global*/ int error (char*);
- /*global*/ int swabcheck (void);
-
- # endif
- #endif
-
- long lseek ();
- char *strcpy ();
- char *calloc ();
- char *realloc ();
- void exit();
- #define V_printf (void) printf
- #define V_fprintf (void) fprintf
- #define V_sprintf (void) sprintf
- #ifdef lint
- void clearerr ();
- #endif
-
- char *my_name = "zap"; /* identification */
- char *usage = "usage: zap [-cdrsvw] file";
-
- /* option flags */
-
- int f_check = FALSE; /* request checksum */
- int f_sum = FALSE; /* print checksum */
- int f_write = FALSE; /* read-write */
- int f_silent = FALSE; /* silent */
- int f_batch = FALSE; /* running batch mode */
- int f_verbose = FALSE; /* give more info */
-
- /* main routine */
-
- main (argc, argv)
- int argc; /* # arguments + 1 */
- char *argv[]; /* argument pointers */
-
- {
- int file_cnt; /* number of files processed */
- char *arg_ptr; /* argument pointer */
- char c; /* current option character */
-
- swabcheck (); /* verify or establish swabbing mode */
-
- /* ignore first argument (program name) */
-
- argc--;
- argv++;
-
- f_batch = !isatty (0);
- file_cnt = 0; /* haven't seen one yet */
-
- while (argc-- > 0) /* through arguments */
- {
- /* fetch a pointer to the current argument, and
- * increase argv
- */
-
- arg_ptr = *argv;
- argv++;
-
- if (*arg_ptr == '-') /* must be an option */
- {
- while (c = *++arg_ptr) /* get option character */
- switch (c)
- {
-
- case 'C' :
- case 'c' :
- f_check = TRUE; /* request checksum */
- break;
-
- case 'D' :
- case 'd' :
- f_sum = TRUE; /* print checksum */
- break;
-
- case 'R' :
- case 'r' :
- f_write = FALSE; /* read-only */
- break;
-
- case 'S' :
- case 's' :
- f_silent = TRUE; /* a little more quiet */
- break;
-
- case 'V' :
- case 'v' :
- V_printf ("zap version 1.9\n");
- #ifndef SWAB
- if (!f_verbose)
- remark ("you may recompile with \"-DSWAB=%ld\"",
- (long)swab);
- #endif
- f_verbose = TRUE; /* a little less quiet */
- break;
- case 'W' :
- case 'w' :
- f_write = TRUE; /* allow write access */
- break;
-
- default : error (usage);
- break;
- }
-
- /* this ends the option processing */
- }
- else
- {
- /* it must be a file specification */
-
- file_cnt++; /* now we've seen one */
-
- zap (arg_ptr);
-
- /* this ends the file processing */
- }
-
- /* this ends the argument processing */
- }
-
- /* if there were no filespecs, give error */
-
- if (!file_cnt)
- error (usage);
-
- /* that's it */
-
- #ifdef vaxc
- return (1);
- #else
- return (0);
- #endif
- }
-
- /* current type values. note - value is also size of type */
-
- int cur_type;
- #define BYTE 1
- #define WORD 2
- #define LWORD 4
-
- char dp_type [] = " \\/ |";
-
- /* current display mode */
-
- int cur_printmode;
- #define OCTAL 0
- #define DECIMAL 1
- #define HEX 2
- #define ASCII 3
-
- char *defffmt[] = { "0%05lo", "%6ld", "x%05lx", "0%05lo" };
- char *deffmt[] = { "0%lo", "%ld", "x%lx", "0%lo" };
-
- #define BYTEVAL(x) ((x) & 0xff)
-
- /* current file */
-
- FILE *zf;
-
- /* get (decimal, hex or octal) value from input line */
- /* a zero return value means : ok */
-
- int decod (buf, lp)
- char *buf;
- long *lp;
- {
- long num;
- char *cp;
- int dooct = FALSE;
- int dohex = FALSE;
- int doasc = FALSE;
-
- num = 0;
- cp = buf;
- if (*cp == ';') /* select mode */
- {
- cp++;
- if (*cp == 'x' || *cp == 'X')
- dohex = TRUE;
- else
- if (*cp == 'o' || *cp == 'O')
- dooct = TRUE;
- else
- if (*cp == 'd' || *cp == 'D')
- ;
- else
- if (*cp == 'a' || *cp == 'A')
- doasc = TRUE;
- else
- V_printf ("input error");
- cp++;
- }
- else
- {
- while (*cp == '0')
- {
- dooct = TRUE;
- cp++;
- }
- if (*cp == 'x' || *cp == 'X')
- {
- cp++;
- dohex = TRUE;
- }
- }
-
- if (dohex)
- {
- while (isxdigit (*cp))
- {
- num = num * 16
- + (isdigit (*cp)
- ? *cp - '0'
- : (*cp | 0x20) - 'a' + 10);
- cp++;
- }
- }
- else
- if (dooct)
- {
- while (isdigit (*cp) && *cp < '8')
- {
- num = num * 8 + *cp - '0';
- cp++;
- }
- }
- else
- if (doasc)
- {
- int i;
- for (i = 0; i < cur_type && *cp; i++)
- {
- if (swab)
- num += ((long)(*cp++)) << (i << 3);
- else
- num = (num << 8) + *cp++;
- }
- }
- else
- {
- while (isdigit (*cp))
- {
- num = num * 10 + *cp - '0';
- cp++;
- }
- }
-
- *lp = num;
- if (!*cp)
- return (0);
- if (*cp == '^')
- return (-1); /* special return value for zap */
- else
- return (1);
- }
-
- /* retrieve byte from file */
-
- unsigned gv_file (addr)
- long addr;
- {
- long l;
-
- if (fseek (zf, addr, 0))
- remark ("cannot position to %ld", addr);
-
- (void) clearerr (zf);
- l = fgetc (zf);
-
- if (l == EOF)
- remark (ferror(zf) ? "cannot read at %ld" : "read beyond eof", addr);
-
- return (BYTEVAL(l));
- }
-
- #define BUF_INC 512
- int tbl_max = BUF_INC;
-
- struct ntry
- {
- long addr;
- char val;
- char old;
- }
- *tbl, /* value table */
- *tbl_cur, /* last referenced entry in table */
- *tbl_free, /* next free entry in table */
- *tbl_ptr; /* work pointer into table */
-
- int locate (adr)
- long adr;
- {
- /* lookup address in table. return tbl_cur at correct entry
- * or next higher */
-
- if (tbl_cur >= tbl && tbl_cur < tbl_free && tbl_cur->addr == adr)
- /* just looked up */
- return (TRUE);
-
- for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
- {
- if (tbl_cur->addr > adr)
- break;
- if (tbl_cur->addr == adr)
- return (TRUE);
- }
- return (FALSE);
- }
-
- enter (addr, val)
- long addr;
- int val;
- {
- char old;
-
- /* lookup address */
- if (locate (addr))
- {
- /* store value, if different from file value */
- if (val != tbl_cur->old)
- {
- tbl_cur->val = val;
- return;
- }
- /* else delete entry from table */
- for (tbl_ptr=tbl_cur; tbl_ptr < tbl_free-1; tbl_ptr++)
- tbl_ptr[0] = tbl_ptr[1];
- tbl_free--;
- return;
- }
-
- /* if not found, tbl_cur points at next higher address entry */
- /* insert new entry at appropriate position */
-
- old = gv_file (addr);
- if (val == old) /* no-op if new == old */
- return;
-
- /* check for space in table, otherwise extend it */
- if (tbl_free == &tbl[tbl_max])
- {
- tbl_max += BUF_INC;
- if ((tbl = (struct ntry*) realloc ((char*) tbl, (unsigned) tbl_max * sizeof (*tbl))) == NULL)
- error ("table overflow");
- }
-
- for (tbl_ptr=tbl_free-1; tbl_ptr >= tbl_cur; tbl_ptr--)
- tbl_ptr[1] = tbl_ptr[0];
-
- tbl_cur->addr = addr;
- tbl_cur->val = val;
- tbl_cur->old = old;
-
- tbl_free++;
- }
-
- /* retrieve value from table */
-
- int get_value (addr)
- long addr;
- {
- int val;
-
- if (locate (addr))
- val = tbl_cur->val;
- else
- val = gv_file (addr);
-
- return (val);
- }
-
- /* put byte into table */
-
- #define put_byte enter
-
- /* put value into table */
-
- put_value (addr, val)
- long addr;
- long val;
- {
- int i;
-
- for (i=0; i<cur_type; i++)
- {
- register long temp = addr + ((swab) ? i : (cur_type-i-1));
- put_byte (temp, (int)BYTEVAL(val));
- val >>= 8;
- }
- }
-
- ptv_file (addr, val)
- long addr;
- char val;
- {
- char c;
-
- c = val;
-
- if (fseek (zf, addr, 0))
- remark ("cannot position to %ld", addr);
-
- (void) clearerr (zf);
- (void) fputc (c, zf);
- if (ferror(zf) || feof(zf))
- remark ("cannot write at %ld", addr);
- }
-
- char buf [132];
- char *pr_val();
-
- #define PREV_MAX 256 /* size of previous goto table */
- long prevs [PREV_MAX]; /* previous goto table */
- int prevcnt; /* next free index in previous table */
-
- push_loc (loc)
- long loc;
- {
- int i;
- if (prevcnt == PREV_MAX)
- {
- for (i=0; i<prevcnt; i++)
- prevs[i] = prevs[i+1];
- prevcnt--;
- }
- prevs[prevcnt++] = loc;
- }
-
- long pop_loc ()
- {
- if (prevcnt > 0)
- return (prevs[--prevcnt]);
- return (0);
- }
-
- long last_value; /* last printed value */
- long sstart; /* search starting value */
- long ennd; /* search ending value */
- long interrupted; /* search was terminated */
- int diddots; /* dots were displayed */
-
- int quit_search ()
- {
- interrupted = sstart;
- sstart = ennd;
- }
-
- foundit (addr)
- long addr;
- {
- if (diddots)
- V_printf ("\n");
- V_printf ("Found at ");
- V_printf (defffmt[cur_printmode], addr);
- V_printf ("\n");
- diddots = FALSE;
- push_loc (addr);
- }
-
- /* search value in file */
-
- search ()
- {
- int bt; /* first byte thereof */
- long first;
- union {
- long ll;
- char ss[4];
- } uu;
-
- if (!gt_val ("Search for ? ", &uu.ll))
- return;
-
- if (!gt_val ("Start at ? ", &sstart))
- return;
-
- if (!gt_val ("Stop at ? ", &ennd))
- return;
-
- /* temporary using first to hold EOF value */
- first = lseek (fileno(zf), 0l, 2);
- if (ennd == 0)
- {
- if (f_verbose)
- {
- V_fprintf (stderr, "EOF at ");
- V_fprintf (stderr, deffmt[cur_printmode], first);
- V_fprintf (stderr, "\n");
- }
- ennd = first - cur_type + 1;
- }
-
- if (sstart > ennd)
- {
- remark ("start > end", 0L);
- return;
- }
-
- if (ennd > first)
- {
- if (f_verbose)
- remark ("end > EOF, truncated", 0L);
- ennd = first;
- }
- /* end of using first to hold EOF value */
-
- #ifndef SEARCH_ACTUAL
- if (fseek (zf, sstart, 0))
- {
- V_fprintf (stderr, "cannot position to ");
- V_fprintf (stderr, deffmt[cur_printmode], sstart);
- V_fprintf (stderr, "\n");
- return;
- }
- #endif
-
- (void) signal (SIGINT, quit_search);
-
- /* shift to align */
- if (!swab)
- {
- if (cur_type == BYTE)
- uu.ss[0] = uu.ss[3];
- else
- if (cur_type == WORD)
- {
- uu.ss[0] = uu.ss[2];
- uu.ss[1] = uu.ss[3];
- }
- }
- bt = BYTEVAL(uu.ss[0]);
-
- first = sstart;
- diddots = interrupted = FALSE;
-
- while (sstart < ennd)
- {
-
- /* print a dot for every 1K processed */
- if (!f_silent && (((first - sstart) & 0x3ff) == 0) && sstart > first)
- {
- V_printf (".");
- (void) fflush (stdout);
- diddots = TRUE;
- }
-
- #ifdef SEARCH_ACTUAL
-
- /* searching the actual values (very slow) */
-
- if (get_value (sstart) == bt)
- {
- if (
- ( cur_type == BYTE /* looking for byte is easy */
- )
- || ( cur_type == WORD /* word needs another byte */
- && (get_value (sstart+1L) == BYTEVAL(uu.ss[1]))
- )
- || ( cur_type == LWORD /* lword needs three other bytes */
- && (get_value (sstart+1L) == BYTEVAL(uu.ss[1]))
- && (get_value (sstart+2L) == BYTEVAL(uu.ss[2]))
- && (get_value (sstart+3L) == BYTEVAL(uu.ss[3]))
- )
- )
- foundit (sstart);
- }
- start++;
-
- #else
-
- /* searching the old contents of the file */
-
- if (fgetc (zf) == bt)
- {
- int chr;
- if (cur_type == BYTE) /* looking for byte is easy */
- foundit (sstart);
- else
- {
- chr = fgetc (zf);
- if (chr == BYTEVAL(uu.ss[1]))
- {
- if (cur_type == WORD)
- {
- foundit (sstart);
- ungetc (chr, zf);
- }
- else
- {
- chr = fgetc (zf);
- if (chr == BYTEVAL(uu.ss[2]))
- {
- chr = fgetc (zf);
- if (chr == BYTEVAL(uu.ss[3]))
- foundit (sstart);
- }
- fseek (zf, sstart+1L, 0);
- }
- }
- else
- ungetc (chr, zf);
- }
- }
- sstart++;
- if (ferror (zf) || feof (zf))
- quit_search ();
-
- #endif
-
- } /* while (sstart < ennd) */
-
- if (diddots)
- V_printf ("\n");
- (void) signal (SIGINT, SIG_DFL);
- if (!f_batch && interrupted)
- {
- V_printf ("Interrupted at ");
- V_printf (defffmt[cur_printmode], sstart);
- V_printf ("\n");
- }
- }
-
- /* print verification list */
-
- verify ()
- {
- long addr = 0;
-
- /* display all modifications entered until now. display in portions
- * of cur_printmode. align to lower cur_type boundary
- */
- for (tbl_ptr = tbl; tbl_ptr != tbl_free; tbl_ptr++)
- if (tbl_ptr->addr >= addr)
- {
- addr = tbl_ptr->addr & ~(cur_type-1);
- V_printf ("vfy: ");
- V_printf (defffmt[cur_printmode], addr);
- V_printf ("%c %-7s => ", dp_type[cur_type], pr_val (addr, FALSE));
- V_printf ("%-7s\n", pr_val (addr, TRUE));
- addr += cur_type;
- }
- }
-
- int gt_line (dst, prompt, arg1, arg2, arg3, arg4)
- char *dst;
- char *prompt;
- long arg1;
- long arg2;
- char arg3;
- char *arg4;
- {
- if (prompt != NULL && !f_silent)
- V_printf (prompt, arg1, arg2, arg3, arg4);
- (void) fflush (stdout);
- if (!gets (dst))
- {
- if (f_batch && !f_silent)
- V_printf ("[eof]\n");
- #ifndef vaxc
- (void) putchar ('\n');
- #endif
- return (NULL);
- }
- if (f_batch && !f_silent)
- V_printf ("%s\n", dst);
- if (dst[0] == '^' && dst[1] == 'Z' && dst[2] == '\0')
- return (FALSE);
- else
- return (TRUE);
- }
-
- int gt_val (prompt, l)
- char *prompt;
- long *l;
- {
- *l = 0l;
- while (gt_line (buf, prompt, 0L, 0L, '\0', NULL))
- {
- if (!decod (buf, l))
- return (TRUE);
- }
- return (FALSE);
- }
-
- /* display value, using current settings (result is in static area) */
-
- char *pr_val (addr, cur)
- long addr;
- int cur; /* 1 = use current, 0 = use previous */
- {
- static char dst [64];
- char *cp;
- long val;
- int i;
- # define getbyte(addr) BYTEVAL((cur) ? get_value (addr) : gv_file (addr))
-
- last_value = 0;
- if (cur_printmode == ASCII)
- {
- cp = dst;
- for (i=0; i<cur_type; i++)
- {
- val = getbyte (addr);
- addr++;
- if (val >= ' ' && val < 0177 && val != '\\')
- *cp++ = val;
- else
- {
- *cp++ = '\\';
- switch ((int)BYTEVAL(val))
- {
- case '\b': *cp++ = 'b';
- break;
- case '\n': *cp++ = 'n';
- break;
- case '\t': *cp++ = 't';
- break;
- case '\f': *cp++ = 'f';
- break;
- case '\r': *cp++ = 'r';
- break;
- case '\\': *cp++ = '\\';
- break;
- default: V_sprintf (cp, "%o", val);
- while (*cp) cp++;
- break;
- }
- }
- *cp++ = ' ';
- }
- *cp = '\0';
- }
- else
- {
- val = 0l;
- switch (cur_type)
- {
- case BYTE:
- val = getbyte (addr);
- break;
- case WORD:
- if (swab) {
- val = getbyte (addr+1L);
- val = (val << 8) | getbyte (addr );
- }
- else {
- val = getbyte (addr );
- val = (val << 8) | getbyte (addr+1L);
- }
- break;
- case LWORD:
- if (swab) {
- val = getbyte (addr+3L);
- val = (val << 8) | getbyte (addr+2L);
- val = (val << 8) | getbyte (addr+1L);
- val = (val << 8) | getbyte (addr );
- }
- else {
- val = getbyte (addr );
- val = (val << 8) | getbyte (addr+1L);
- val = (val << 8) | getbyte (addr+2L);
- val = (val << 8) | getbyte (addr+3L);
- }
- break;
- }
- if ((last_value = val) != 0 || cur_printmode != OCTAL)
- V_sprintf (dst, deffmt[cur_printmode], val);
- else
- (void) strcpy (dst, "0");
- }
-
- return (dst);
- }
-
- zap (fname)
- char *fname;
-
- {
- long base; /* base of patching sequence */
- long offset; /* offset from base */
- long val; /* holding variable for values */
- int i; /* scratch */
- char chr; /* scratch */
- int check; /* checksum value */
- int need_head; /* header toggle */
- int checkwrite = TRUE; /* check for write access */
- int goon = TRUE; /* until ^Y is used */
- static char *fmt [] = {
- "0%05lo 0%05lo%c %-7s ",
- "%6ld %6ld%c %-7s ",
- "x%05ld x%05lx%c %-7s ",
- "0%05lo 0%05lo%c %-7s " };
-
- /* open file */
-
- #ifdef MSDOS
- if ((zf = fopen (fname, (f_write) ? "rb+" : "rb")) == NULL)
- #else
- if ((zf = fopen (fname, (f_write) ? "r+" : "r")) == NULL)
- #endif
- cant (fname);
-
- /* set defaults and allocate table */
-
- cur_type = BYTE;
- cur_printmode = OCTAL;
- if (!tbl)
- tbl = (struct ntry*) calloc ((unsigned)tbl_max, sizeof (struct ntry));
- if (!tbl)
- error ("no room for table");
- tbl_cur = tbl_free = tbl;
- prevcnt = 0; /* reset previous location table */
-
- /* loop 1 : loop on Base values */
-
- while (goon && gt_val ("Base ? ", &base))
- {
- /* loop 2 : loop on offset values */
-
- while (goon && gt_val ("Offset ? ", &offset))
- {
- need_head = TRUE;
-
- /* loop 3 : loop on patch commands */
-
- while (goon)
- {
- if (need_head && !f_silent)
- V_printf ("Base Offset Value New\n");
- need_head = FALSE;
-
- if (!gt_line (buf, fmt[cur_printmode], base, offset,
- dp_type[cur_type], pr_val (base+offset, TRUE)))
- break;
-
- switch (buf[0])
- {
- case '\0':
- /* close current, advance and open new location */
- offset += cur_type;
- break;
- case '/':
- /* re-open current using new type */
- cur_type = WORD;
- break;
- case '\\':
- /* re-open current using new type */
- cur_type = BYTE;
- break;
- case '|':
- /* re-open current using new type */
- cur_type = LWORD;
- break;
- case '^':
- if (buf[1] == '\0')
- {
- /* close current, backup and open new location */
- offset -= cur_type;
- break;
- }
- if (buf[1] != 'Y' || buf[2] != '\0')
- break;
- /* FALL THROUGH */
- case '\031': /* ^Y */
- goon = FALSE;
- break;
- case '>':
- /* goto new location */
- if (!decod (&buf[1], &val))
- {
- push_loc (base+offset);
- offset = buf[1] ? val : last_value;
- }
- break;
- case '<':
- /* goto location */
- if (buf[1] == '\0' && prevcnt > 0)
- offset = pop_loc () - base;
- break;
- case ';':
- /* change current display mode ... */
- chr = buf[1];
- if (isupper (chr))
- chr = tolower (chr);
- if (chr == 'o')
- cur_printmode = OCTAL;
- else
- if (chr == 'd')
- cur_printmode = DECIMAL;
- else
- if (chr == 'x')
- cur_printmode = HEX;
- else
- /* ... or store ascii bytes ... */
- if (chr == 'a')
- {
- cur_printmode = ASCII;
- for (i=2; chr=buf[i]; i++)
- {
- if (checkwrite && !f_write)
- {
- need_head = TRUE;
- checkwrite = FALSE;
- remark ("no write access", 0L);
- }
- put_byte (base+offset, chr);
- offset++;
- }
- }
- else
- /* ... or print modifications ... */
- if (chr == 'v')
- {
- verify ();
- need_head = TRUE;
- }
- else
- /* ... or search values */
- if (chr == 's')
- {
- search ();
- need_head = TRUE;
- }
-
- break;
- default:
- if ((i = decod (buf, &val)) <= 0)
- {
- if (checkwrite && !f_write)
- {
- need_head = TRUE;
- checkwrite = FALSE;
- remark ("no write access", 0L);
- }
- put_value (base+offset, val);
- if (!i)
- offset += cur_type;
- else
- offset -= cur_type;
- }
- }
- /* loop on patch commands */
- }
- /* loop on offset values */
- }
- /* loop on base values */
- }
-
- /* compute checksum, if requested */
-
- if (f_check || f_sum)
- {
- check = 0;
- for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
- check ^= (BYTEVAL(tbl_cur->val) | ((tbl_cur->old << 8) & 0xff00));
- if (f_sum)
- {
- V_printf ("Checksum = ");
- V_printf (deffmt[cur_printmode], check);
- V_printf ("\n");
- }
- }
-
- /* apply patches, after checksum verification */
-
- tbl_cur = tbl;
-
- if (f_write)
- {
- /* verify checksum */
-
- if (f_check)
- while (gt_val ("Checksum ? ", &val))
- if (val == check || f_batch)
- break;
-
- if (!(f_check && val != check))
- for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
- ptv_file (tbl_cur->addr, tbl_cur->val);
- }
-
- if (tbl_cur != tbl_free)
- error ("no modifications made");
-
- if (!f_silent && f_write && tbl == tbl_free)
- remark ("no modifications requested", 0L);
-
- /* close file and exit */
-
- (void) fclose (zf);
- }
-
- cant (s)
- char *s;
- {
- V_fprintf (stderr, "%s: cannot open %s\n", my_name, s);
- exit (1);
- }
-
- remark (s, a)
- char *s;
- long a;
- {
- V_fprintf (stderr, "%s: ", my_name);
- V_fprintf (stderr, s, a);
- V_fprintf (stderr, "\n");
- }
-
- error (s)
- char *s;
- {
- V_fprintf (stderr, "%s: %s\n", my_name, s);
- exit (1);
- }
-
- swabcheck ()
- {
- union {
- short s;
- char a[2];
- } u;
- u.s = 0x1357;
- #ifdef SWAB
- #if SWAB
- if (!(u.a[0] == 0x57 && u.a[1] == 0x13))
- error ("please recompile with \"-DSWAB=0\"");
- #else
- if (!(u.a[0] == 0x13 && u.a[1] == 0x57))
- error ("please recompile with \"-DSWAB=1\"");
- #endif
- #else
- swab = (u.a[0] == 0x57 && u.a[1] == 0x13);
- #endif
- #ifdef lint
- SCCS_id[0] = cprght[0] = '\0';
- #endif
- }
- SHAR_EOF
- if test 24693 -ne "`wc -c < 'zap.c'`"
- then
- echo shar: "error transmitting 'zap.c'" '(should have been 24693 characters)'
- fi
- fi
- if test -f 'zap.1'
- then
- echo shar: "will not over-write existing file 'zap.1'"
- else
- cat << \SHAR_EOF > 'zap.1'
- .TH ZAP 1
- .ad b
- .SH NAME
- zap \- binary inspect or modify files
- .PP
- .SH SYNOPSIS
- .PP
- .B zap
- .\" single character options
- .RB [ \-cdrsvw ]
- .\" options with a value
- .\" name arguments
- file
- .SH VERSION INFO
- .PP
- @(#)@ ZAP 1.9 - 87/11/04
- .br
- Written by Johan Vromans at Multihouse Research, Gouda, the Netherlands.
- .br
- Copyright 1987 Johan Vromans.
- .br
- Distribution free as long as you give credit to the original author.
- .br
- .Military use and explicit resale prohibited.
- .br
- Usage of this program is always at your own risk.
- .SH DESCRIPTION
- .PP
- .I Zap\^
- can be used to inspect and/or modify files. It regards the file as a
- sequence of bytes, words (2 bytes) or longwords (4 bytes). Changes are
- buffered, and only applied to the file upon normal completion. Only
- real changes are considered a modification, e.g. a change of 1 to 1 is
- a no-operation, and a change of 1 to 2 and then again to 1 discards
- the modification.
- .PP
- Input may be redirected from a file for batch-mode patching.
- .PP
- .I Zap\^
- regards locations in a file to be an
- .I offset
- to a
- .IR base .
- After invokation,
- .I zap
- asks for the base value. When end-of-file is issued, the program
- terminates. After the base value has been entered,
- .I zap
- asks for the offset value. End-of-file makes it go back to the "Base"
- prompt. After the offset value is entered,
- .I zap
- displays
- the offset, base and contents of the current location, and
- waits for commands to execute.
- Typing end-of-file to the command prompt makes
- .I zap
- go back to the "Offset" question.
- .PP
- .I Zap
- operates in one of three modes: byte, word or longword. Words and
- longwords need not be aligned. The current mode is identified by a
- "\e" for byte, "/" for word and "|" for longword mode.
- .br
- The contents of a location are displayed in one of four formats: octal,
- decimal, hexadecimal or ascii. See the commands how to change this format.
- In ascii format, some interpretation is made to show special control
- characters.
- .PP
- An example of
- .IR zap 's
- output (user input in bold):
- .sp
- .in +.5i
- .nf
- Base ? \fB0100\fP
- Offset ? \fB0200\fP
- Base Offset Value New
- 000100 000200\e 0130 \fB/\fP
- 000100 000200/ 054117
- 000100 000202/ 045200
- 000100 000204/ 063004 \fB^Z\fP
- Offset ? \fB^Z\fP
- Base ? \fB^Z\fP
- .in
- .fi
- .PP
- Each command is terminated by a <newline>. Valid commands are:
- .PP
- .I
- Changing mode
- .sp
- .TP 7
- .B \e
- change to byte mode.
- .TP
- .B /
- change to word (2-byte) mode.
- .TP
- .B |
- change to longword (4-byte) mode.
- .PP
- .I
- Changing display format
- .TP 7
- .B ;a
- change display format to ascii.
- In ascii format, the base and offset values are displayed in octal.
- .TP
- .B ;d
- change display format to decimal.
- .TP
- .B ;o
- change display format to octal.
- .TP
- .B ;x
- change display format to hexadecimal.
- .PP
- .I
- Moving around
- .TP 7
- <empty>
- an empty line advances to the next location.
- .TP
- .B ^
- a caret backs up to the previous location.
- .TP
- .BI > nnn
- moves
- .I offset
- to the specified location. If
- .I nnn
- is omited, the contents of the current location are used.
- The current location is saved in the location table.
- Up to 256 saved locations can be restored in a last-in
- first-out manner.
- .TP
- .B <
- move back to the most recently saved location.
- .PP
- .I
- Modifying contents
- .TP 7
- .I nnn
- the contents of the current location are set to
- .IR nnn .
- This can be an octal, decimal or a hexadecimal number in the form
- .I nnn
- (decimal),
- .BI 0 nnn
- (octal),
- .BI 0x nnn
- (hex).
- The offset is advanced to the next location.
- .TP
- .IB nnn ^
- the contents of the current location are set to
- .I nnn
- as described above.
- The offset is backed up to the previous location.
- .TP
- .BI ;a abc
- change display format to ascii, and store the ascii characters
- .I abc
- starting from the current location. Any number of caracters can be
- stored this way. The current offset is advanced to the next location.
- .PP
- .I
- Miscellaneous commands
- .TP 7
- .B ;v
- verify - prints a list of pending modifications.
- .TP
- .B ;s
- search - asks for a search value and boundaries, and then searches
- for the specfied value. The locations where it is found are printed, and
- also stored in the location table.
- .br
- The search applies to the file contents only, any pending modifications are
- ignored during the search.
- .br
- The argument to the search can be supplied numerically (decimal, octal or
- hex), or in the format
- .BI ;a pqr
- which causes it to be interpreted as an ascii search argument. The number
- of characters allowed depends on the current mode of operation: 1 for byte
- mode, 2 for word mode, and 4 for longword mode.
- .br
- A search can be interrupted using the terminal interrupt signal.
- Note that the current mode controls the search. If zap is in byte mode, the
- search is for a byte, and so on. When searching for words or longwords,
- word boundaries are ignored.
- .br
- During the search, a "." is displayed for each 1024 bytes processed. This
- can be suppressed with the
- .B \-s
- command line option.
- .TP
- .B ^Y
- (caret-uppercase-Z or control/Y) terminates the
- .I zap
- loop without asking for new offset/base values.
- .TP
- .B ^Z
- (caret-uppercase-Z) can be used as end-of-file signal. It's main use is in
- batch files.
- .PP
- The following options may be given (in any order)
- before the file-name argument:
- .PP
- .TP 7
- .B \-c
- calculates a 16-bit checksum involving all modifications. The order in
- which the modifications are made is not important.
- .I Zap
- requests a checksum value to be entered upon completion, and
- requires this value to match the checksum. If they differ, no
- modifications are made.
- .TP
- .B \-d
- calculates the checksum and print its value upon completion.
- .TP
- .B \-r
- access the
- .I file
- for inspection only. This is the default.
- .TP
- .B \-s
- work silently. No prompts and remarks are displayed. This can be used
- for batch-like processing, if input has been re-directed from a file.
- .TP
- .B \-v
- Supply informational messages.
- .TP
- .B \-w
- access the
- .I file
- in a mode which allows modification.
- .SH DIAGNOSTICS
- .TP 7
- no write access
- a modification is made, and the
- .B \-w
- option was not supplied. This message is showed only once.
- .TP
- no modifications made
- the file has not been modified, either because the
- .B \-w
- option was missing, or the requested checksum did not match.
- This situation is considered an error.
- .TP
- no modifications requested
- the file was accessed using the
- .B \-w
- option, but no changes were pending. This is an informational message.
- .TP
- input error
- an invalid input format was supplied to a numeric prompt. The question is
- repeated.
- .TP
- start > end
- (warning) the end value for a search exceeded the starting position. The
- search is not executed.
- .TP
- EOF > end, truncated
- (warning) the end value for a search exceeded the end-of-file. The end-of-file value
- is used.
- .TP
- you may recompile with "-DSWAB=\fIX\fP"
- (informational)
- .I zap\^
- found out that your system swabs bytes (\fIX\fP = 1) or not (\fX\fP = 0).
- You may use this in a subsequent compilation.
- .TP
- please recompile with "-DSWAB=\fIX\fP"
- (fatal)
- .I zap\^
- found out that your system swabs bytes (\fIX\fP = 1) or not (\fX\fP = 0),
- but the opposite was specified during compilation. You will have to
- recompile with the correct value.
- .PP
- messages from reading/writing/positioning the file.
- .SH BUGS
- .PP
- Usage of this program is at your own risk. Use
- .IR cmp (1)
- to verify any changes.
- .SH AUTHORS
- .PP
- Johan Vromans - Multihouse Research.
- .sp
- USENET: jv@mh.nl via european backbone mcvax.
- .PP
- There may be some resemblance with an RT-11 program called SIPP.
- SHAR_EOF
- if test 7418 -ne "`wc -c < 'zap.1'`"
- then
- echo shar: "error transmitting 'zap.1'" '(should have been 7418 characters)'
- fi
- fi
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- # Makefile for zap
-
- # Define SWAB to 1 if your machine swabs bytes, like a vax, otherwise use
- # the value 0.
- # A number of systems types are already known to zap, like vax, pdp11
- # and intel processors.
- # If you do this wrong, zap will abort with an appropriate message.
- # Define SWAB=2 if you want to force zap to find out itself, running
- # 'zap -i' will give you advise.
-
- #SWAB = # unknown (uses built-ins if possible, or find out)
- #SWAB = -DSWAB=0 # normal system
- #SWAB = -DSWAB=1 # vax
- #SWAB = -DSWAB=2 # unknown (overrides built-ins)
-
- CFLAGS = -O -s
-
- zap: zap.c
- $(CC) $(CFLAGS) $(SWAB) zap.c -o zap
-
- # change these for your site
-
- DESTDIR = /usr/local/bin
- DSTOWN = bin
- DSTGRP = bin
- MANDIR = /usr/local/man/man1
-
- install: zap
- cp zap $(DESTDIR)/zap
- chmod 0755 $(DESTDIR)/zap
- chgrp $(DSTGRP) $(DESTDIR)/zap
- chown $(DSTOWN) $(DESTDIR)/zap
- cp zap.1 $(MANDIR)/zap.1
- chmod 0644 $(MANDIR)/zap.1
- chgrp $(DSTGRP) $(MANDIR)/zap.1
- chown $(DSTOWN) $(MANDIR)/zap.1
-
- SOURCES = Read.Me zap.c zap.1 Makefile mkzap.com mkzap.bat
- SHAR = zap.shar
-
- zap.shar:
- shar -c $(SOURCES) > $(SHAR)
-
- clean:
- rm -f $(SOURCES) $(SHAR) zap zap.o a.out core
- SHAR_EOF
- if test 1137 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: "error transmitting 'Makefile'" '(should have been 1137 characters)'
- fi
- fi
- if test -f 'mkzap.com'
- then
- echo shar: "will not over-write existing file 'mkzap.com'"
- else
- cat << \SHAR_EOF > 'mkzap.com'
- $! compile & link zap for VAX/VMS
- $!
- $ cc /define=(SWAB=2) zap.c
- $ link zap,sys$library:vaxcrtl/lib
- $!
- $! invoke by symbol
- $!
- $ zap :== $'f$environment("default")'zap.exe
- $!
- SHAR_EOF
- if test 174 -ne "`wc -c < 'mkzap.com'`"
- then
- echo shar: "error transmitting 'mkzap.com'" '(should have been 174 characters)'
- fi
- fi
- if test -f 'mkzap.bat'
- then
- echo shar: "will not over-write existing file 'mkzap.bat'"
- else
- cat << \SHAR_EOF > 'mkzap.bat'
- rem compile & link zap for ms-dos
-
- cl -DLINT_ARGS zap.c
- SHAR_EOF
- if test 56 -ne "`wc -c < 'mkzap.bat'`"
- then
- echo shar: "error transmitting 'mkzap.bat'" '(should have been 56 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-
-